//============================================================================================
/**
 * @file	head_result.c
 * @brief
 * @date	2009.02.07
 * @author	NozomuSaito GAME FREAK inc.
 *
 * モジュール名：HeadRslt_
 */
//============================================================================================

#include "common.h"
#include "fieldsys.h"
#include "encount_set.h"
#include "field_encount.h"

#include "head_result.h"

#define POS_DATA_NUM	(6)

static BOOL HeadRsltEvt(GMEVENT_CONTROL *event);

typedef struct HEAD_POS_DATA_tag
{
	s16 X;
	s16 Z;
}HEAD_POS_DATA;

typedef struct HEAD_EVT_WORK_tag
{
	u16* AnsWk;
}HEAD_EVT_WORK;

static s8 CheckHeadPos(	const u16 inNrmNum, const u16 inSpNum,
						const u32 inPlayerID,
						const int inX, const int inZ,
						HEAD_POS_DATA *inData);
static s8 CalcHeadEncType(const u8 inNum, const u8 inNrmNum, const u32 inPlayerID);
static void GetHeadPoint(FIELDSYS_WORK *fsys, int *outX, int *outZ);

static const s8 EncType5[10][5] = {
	{-1,0,0,1,1},	//	C	A	A	B	B
	{1,-1,0,0,1},	//	B	C	A	A	B
	{1,1,-1,0,0},	//	B	B	C	A	A
	{0,1,1,-1,0},	//	A	B	B	C	A
	{0,0,1,1,-1},	//	A	A	B	B	C
	{-1,0,1,0,1},	//	C	A	B	A	B
	{1,-1,0,1,0},	//	B	C	A	B	A
	{0,1,-1,0,1},	//	A	B	C	A	B
	{1,0,1,-1,0},	//	B	A	B	C	A
	{0,1,0,1,-1},	//	A	B	A	B	C
};

static const s8 EncType4[10][4] = {
	{-1,0,0,1},		//	C	A	A	B
	{1,-1,0,0},		//	B	C	A	A
	{1,1,-1,0},		//	B	B	C	A
	{0,1,1,-1},		//	A	B	B	C
	{0,0,1,1},		//	A	A	B	B
	{-1,0,1,0},		//	C	A	B	A
	{1,-1,0,1},		//	B	C	A	B
	{0,1,-1,0},		//	A	B	C	A
	{1,0,1,-1},		//	B	A	B	C
	{0,1,0,1},		//	A	B	A	B
};

static const s8 EncType3[10][3] = {
	{0,1,-1},		//	A	B	C
	{0,-1,1},		//	A	C	B
	{1,0,-1},		//	B	A	C
	{1,-1,0},		//	B	C	A
	{-1,0,1},		//	C	A	B
	{-1,1,0},		//	C	B	A
	{0,1,-1},		//	A	B	C
	{0,-1,1},		//	A	C	B
	{1,0,-1},		//	B	A	C
	{1,-1,0},		//	B	C	A
};

static const s8 EncType2[10][2] = {
	{0,1},			//	A	B
	{1,0},			//	B	A
	{0,1},			//	A	B
	{1,0},			//	B	A
	{0,1},			//	A	B
	{1,0},			//	B	A
	{0,1},			//	A	B
	{1,0},			//	B	A
	{0,1},			//	A	B
	{1,0},			//	B	A
};

static const s8 EncType1[10] = {
	0,				//	A
	1,				//	B
	0,				//	A
	1,				//	B
	0,				//	A
	1,				//	B
	0,				//	A
	1,				//	B
	0,				//	A
	1,				//	B
};

//--------------------------------------------------------------
/**
 * 頭突き使用後のイベント判定
 * @param	fsys		フィールドシステムポインタ
 * @param	ans_wk		アンサーワークポインタ
 * @retval	none
 */
//--------------------------------------------------------------
void HeadRslt_CallEvt(FIELDSYS_WORK *fsys, u16 *ans_wk)
{
	HEAD_EVT_WORK *wk;

	wk = sys_AllocMemoryLo( HEAPID_WORLD, sizeof(HEAD_EVT_WORK) );

	wk->AnsWk = ans_wk;
	*wk->AnsWk = 0;

	FieldEvent_Call(fsys->event, HeadRsltEvt, wk);
}

//--------------------------------------------------------------
/**
 * 頭突き後イベント
 * @param	event	GMEVENT_CONTROL *
 * @retval	int		TRUE=終了
 */
//--------------------------------------------------------------
static BOOL HeadRsltEvt(GMEVENT_CONTROL *event)
{
	void *data;
	int zone_id;
	GS_HEAD_ENC_DATA* enc_data;


	BOOL rc;
	BATTLE_PARAM *bt_param;
	FIELDSYS_WORK *fsys = FieldEvent_GetFieldSysWork( event );
	HEAD_EVT_WORK *wk = FieldEvent_GetSpecialWork( event );

	zone_id = fsys->location->zone_id;
	OS_Printf("エンカウントするゾーン:%d\n",zone_id);

	data = ArchiveDataLoadMallocLo(ARC_HEAD_DATA, zone_id, HEAPID_WORLD);

	enc_data = (GS_HEAD_ENC_DATA*) data;
	if ( (enc_data->NrmNum != 0)||(enc_data->SpNum != 0) ){
		HEAD_ENC_MONS_DAT *enc_mons_data;
		int x,z;
		s8 type_idx;
		u8 *byte_data;
		HEAD_POS_DATA *pos_data;
		byte_data = (u8*)data;
		byte_data += (sizeof(GS_HEAD_ENC_DATA));
		//頭突きの場所が、当たりかを調べる
		pos_data = (HEAD_POS_DATA *)byte_data;
		//頭突き座標取得
		GetHeadPoint(fsys, &x, &z);
		type_idx = CheckHeadPos(enc_data->NrmNum, enc_data->SpNum,
								MyStatus_GetID(SaveData_GetMyStatus(fsys->savedata)),
								x, z,
								pos_data);
		OS_Printf("type = %d\n",type_idx);

		if (type_idx == -1){
			//エンカウントしない
			sys_FreeMemoryEz(data);
			sys_FreeMemoryEz(wk);
			return TRUE;
		}
		if (type_idx == 0){
			enc_mons_data = enc_data->MonsDatA;
		}else if(type_idx == 1){
			enc_mons_data = enc_data->MonsDatB;
		}else if(type_idx == 2) {
			enc_mons_data = enc_data->MonsDatD;
		}else{
			GF_ASSERT(0);
			sys_FreeMemoryEz(data);
			sys_FreeMemoryEz(wk);
			return TRUE;
		}

		//エンカウントチェック
		rc = SetHeadEncount( fsys, &bt_param, enc_mons_data);
		if ( rc ){
			*wk->AnsWk = 1;	//エンカウントする

			//ワーク解放
			sys_FreeMemoryEz(data);
			sys_FreeMemoryEz(wk);
			FieldEncount_Change( fsys, event, bt_param );
			return FALSE;
		}
	}

	sys_FreeMemoryEz(data);
	sys_FreeMemoryEz(wk);

	return TRUE;
}

//--------------------------------------------------------------
/**
 * 頭突き座標を調べる
 *
 * @param	inNrmNum		通常ポイント座標数
 * @param	inSpNum			特殊ポイント座標数
 * @param	inPlayerID		プレーヤーＩＤ
 * @param	inX
 * @param	inZ
 * @param	inData
 *
 * @retval	s8		エンカウントするテーブルタイプ
 */
//--------------------------------------------------------------
static s8 CheckHeadPos(	const u16 inNrmNum, const u16 inSpNum,
						const u32 inPlayerID,
						const int inX, const int inZ,
						HEAD_POS_DATA *inData)
{
	u16 i;
	u16 nrm_num = inNrmNum*POS_DATA_NUM;
	u16 sp_num = inSpNum*POS_DATA_NUM;

	OS_Printf("データ総数%d\n",nrm_num);
	OS_Printf("プレーヤーＩＤ:%u\n",inPlayerID);
	OS_Printf("頭突き座標:%d,%d\n",inX,inZ);
	for (i=0;i<nrm_num;i++){
		OS_Printf("nrm = %d_%d\n",inData[i].X, inData[i].Z);
		if ((inX == inData[i].X)&&(inZ == inData[i].Z)){
			//インデックスとプレーヤーＩＤからタイプを決定
			return CalcHeadEncType(i/POS_DATA_NUM, inNrmNum, inPlayerID);
		}
	}

	for (i=nrm_num;i<nrm_num+sp_num;i++){
		OS_Printf("sp = %d_%d\n",inData[i].X, inData[i].Z);
		if ((inX == inData[i].X)&&(inZ == inData[i].Z)){
			//固定ポイントにヒット
			return 2;
		}
	}
	return -1;
}

//--------------------------------------------------------------
/**
 * インデックスとプレーヤーＩＤからタイプを決定
 * @param	inNum		木ナンバー
 * @param	inNrmNum	総数(無効データを含む)
 * @param	inPlayerID	プレーヤーＩＤ
 *
 * @retval	 type	エンカウントタイプ
 */
//--------------------------------------------------------------
static s8 CalcHeadEncType(const u8 inNum, const u8 inNrmNum, const u32 inPlayerID)
{
	s8 type = -1;
	u8 no = inPlayerID % 10;
	u8 idx;

	OS_Printf("tree no = %d\n",inNum);

	if (inNrmNum >= 5){
		idx = inNum%5;
		type = EncType5[no][idx];
	}else if(inNrmNum == 4){
		idx = inNum;
		type = EncType4[no][idx];
	}else if(inNrmNum == 3){
		idx = inNum;
		type = EncType3[no][idx];
	}else if (inNrmNum == 2){
		idx = inNum;
		type = EncType2[no][idx];
	}else if(inNrmNum == 1){
		type = EncType1[no];
	}else{
		GF_ASSERT(0);
	}

	return type;
}

//--------------------------------------------------------------
/**
 * 	頭突き座標を取得
 * @param	fsys		フィールドシステムポインタ
 * @param	outX		X座標格納バッファ
 * @param	outZ		Z座標格納バッファ
 *
 * @retval	none
 */
//--------------------------------------------------------------
static void GetHeadPoint(FIELDSYS_WORK *fsys, int *outX, int *outZ)
{
	int x,z;
	//自機の前方座標を取得
	Player_DirFrontGridPosGet( fsys->player, &x, &z );

	if ( PairPoke_IsPairPoke(fsys) ){		//連れ歩きいる
		//連れ歩きポケに座標と比較
		FIELD_OBJ_PTR fldobj = PairPoke_GetFldObjPtr(fsys);
		int px = FieldOBJ_NowPosGX_Get( fldobj );
		int pz = FieldOBJ_NowPosGZ_Get( fldobj );
		//連れ歩きポケと同じ座標か？
		if ( (x == px)&&(z == pz) ){			//連れ歩きと同じ座標
			u8 dir = FieldOBJ_DirDispGet( fldobj );
			//頭突き座標は連れ歩きの前方
			x = px + FieldOBJ_DirAddValueGX( dir );
			z = pz + FieldOBJ_DirAddValueGZ( dir );
		}
	}

	*outX = x;
	*outZ = z;
}

